﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Futaba.SBus.Extensions
{
	/// <summary>
	/// Provides extension-methods to the <see cref="string"/> class
	/// </summary>
	public static class StringExtensions
	{

		private static readonly NumberStyles ParsingNumberStyle = NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
		private static readonly Regex CoordinateRegex = new Regex(@"(?in)(?<position>[NESW])?\s?(?<degrees>\d+)[:° ](?<minutes>\d+\.\d+)$");
		private static readonly char[] NegativeCoordinates = new[] { 'W', 'S' };
		
		/// <summary>
		/// Converts a GPS coordinate from degrees, minutes ([NESW]_DD{°: }MM.mmm[m]) to a (negative for W and S coordinates) double degrees (DD.ddddd) format.
		/// If no direction is specified, positive (N/E) is assumed. [] is optional, one value within {} is required
		/// </summary>
		public static bool TryParseCoordinate(this string valueOrig, out double value)
		{
			value = 0;
			var match = CoordinateRegex.Match(valueOrig);
			if (!match.Success) return false;

			//https://maps.google.at/maps?q=48.015503,+16.164701&num=1&t=h&vpsrc=0&ie=UTF8&z=17&iwloc=A
			//http://stackoverflow.com/questions/4504956/formatting-double-to-latitude-longitude-human-readable-format
			double degrees, minutes, seconds;
			degrees = double.Parse(match.Groups["degrees"].Value, ParsingNumberStyle, CultureInfo.InvariantCulture);
			minutes = double.Parse(match.Groups["minutes"].Value, ParsingNumberStyle, CultureInfo.InvariantCulture);
			seconds = 0D; // double.Parse(match.Groups["seconds"].Value, CultureInfo.InvariantCulture);
			var result = (degrees) + (minutes) / 60 + (seconds) / 3600;

			if (match.Groups["position"].Success)
			{
				char position = match.Groups["position"].Value[0];
				value = NegativeCoordinates.Contains(position) ? -result : result;
			}
			else
			{
				value = result;
			}

			value = Math.Round(value, 5);
			return true;
		}

	}
}
